package com.province.platform.core.utils;

import com.province.platform.common.constants.Constants;
import com.province.platform.common.enums.PluginType;
import com.province.platform.common.exception.PlatformException;
import com.province.platform.common.utils.Configuration;
import com.province.platform.common.enums.CommonErrorCode;
import com.province.platform.core.constants.CoreConstants;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

public class ConfigParser {
    private static final Logger LOG = LoggerFactory.getLogger(ConfigParser.class);

    public static Configuration parse(final String path) {
        Configuration configuration = ConfigParser.parseConfig(path);

        // todo 合并核心配置

        String readerPluginName = configuration.getString(CoreConstants.JOB_CONTENT_READER_NAME);
        String writerPluginName = configuration.getString(CoreConstants.JOB_CONTENT_WRITER_NAME);

        Set<String> pluginList = new HashSet<>();
        pluginList.add(readerPluginName);
        pluginList.add(writerPluginName);

        try {
            configuration.merge(parsePluginConfig(new ArrayList<String>(pluginList)), false);
        } catch (Exception e) {
            LOG.warn(String.format("插件[%s]加载失，败1s后重试... Exception:%s", readerPluginName, e.getMessage()));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                //
            }
            configuration.merge(parsePluginConfig(new ArrayList<String>(pluginList)), false);
        }

        return configuration;
    }

    public static Configuration parsePlatformConfig(String name, String env) {
        Configuration configuration = Configuration.newDefault();

        Properties properties = getPlatformProperties();

        try {
            Class<?> clazz = Class.forName(Constants.KEY_CLASS);

            Field[] fields = clazz.getDeclaredFields();

            for (Field field: fields) {
                if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && field.getType().equals(String.class)) {
                    String key = (String) field.get(null);

                    String val = properties.getProperty(StringUtils.join(new String[]{name, env, key}, "."));
                    if (StringUtils.isBlank(val)) {
                        throw PlatformException.asPlatformException(CommonErrorCode.CONFIG_ERROR, String.format("配置文件[%s]缺少键[%s]", CoreConstants.PLATFORM_CONFIG, key));
                    }
                    
                    configuration.set(field.getName(), SecretUtils.decryptAES(val));
                }
            }
        } catch (ClassNotFoundException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        return configuration;
    }

    private static Properties getPlatformProperties() {
        InputStream stream;
        try {
            File file = new File(CoreConstants.PLATFORM_CONFIG_PATH);
            if (file.exists()) {
                stream = new FileInputStream(file);
            } else {
                stream = SecretUtils.class.getResourceAsStream(CoreConstants.PLATFORM_CONFIG);
            }
        } catch (FileNotFoundException e) {
            throw PlatformException.asPlatformException(CommonErrorCode.SECRET_ERROR, String.format("找不到配置文件[%s]", CoreConstants.PLATFORM_CONFIG));
        }

        Properties properties = new Properties();
        try {
            properties.load(stream);

            if (Objects.nonNull(stream)) {
                stream.close();
            }
        } catch (IOException e) {
            throw PlatformException.asPlatformException(CommonErrorCode.SECRET_ERROR, String.format("读取配置文件[%s]出错", CoreConstants.PLATFORM_CONFIG), e);
        }

        return properties;
    }

    public static Configuration parsePluginConfig(List<String> pluginNames) {
        Configuration configuration = Configuration.newDefault();

        Set<String> repeatCheckPlugin = new HashSet<>();
        int complete = 0;
        for (final String path: getDirAsList(CoreConstants.PLUGIN_READER_HOME)) {
            Configuration eachConfig = ConfigParser.parseOnePluginConfig(path, PluginType.READER.value(), repeatCheckPlugin, pluginNames);
            if (Objects.nonNull(eachConfig)) {
                configuration.merge(eachConfig, true);
                complete += 1;
            }
        }

        for (final String path: getDirAsList(CoreConstants.PLUGIN_WRITER_HOME)) {
            Configuration eachConfig = ConfigParser.parseOnePluginConfig(path, PluginType.WRITER.value(), repeatCheckPlugin, pluginNames);
            if (Objects.nonNull(eachConfig)) {
                configuration.merge(eachConfig, true);
                complete += 1;
            }
        }

        if (pluginNames != null && !pluginNames.isEmpty() && pluginNames.size() == complete) {
            throw PlatformException.asPlatformException(CommonErrorCode.PLUGIN_INIT_ERROR, "插件加载失败，未完成指定插件加载: " + pluginNames);
        }

        return configuration;
    }

    private static Configuration parseOnePluginConfig(final String path, final String type, Set<String> pluginSet, List<String> pluginNames) {
        String filePath = path + File.separator + "plugin.json";
        Configuration configuration = Configuration.from(new File(filePath));

        String pluginName = configuration.getString("name");
        String pluginPath = configuration.getString("path");
        if (!pluginSet.contains(pluginName)) {
            pluginSet.add(pluginName);
        } else {
            throw PlatformException.asPlatformException(CommonErrorCode.PLUGIN_INIT_ERROR, "插件加载失败,存在重复插件:" + filePath);
        }

        if (pluginNames != null && !pluginNames.isEmpty() && !pluginNames.contains(pluginName)) {
            return null;
        }

        if (StringUtils.isBlank(pluginPath)) {
            configuration.set("path", path);
            configuration.set("loadType", "jarLoader");
        }

        Configuration result = Configuration.newDefault();
        result.set(String.format("plugin.%s.%s", type, pluginName), configuration.getContent());

        return result;
    }

    private static Configuration parseConfig(String path) {
        String configContent = getConfigContent(path);

        Configuration config = Configuration.from(configContent);

        return SecretUtils.decryptSecretKey(config);
    }

    private static String getConfigContent(String path) {
        String configContent;

        try {
            configContent = FileUtils.readFileToString(new File(path), StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw PlatformException.asPlatformException(CommonErrorCode.CONFIG_ERROR, "读取配置文件失败: " + path);
        }

        return configContent;
    }

    private static List<String> getDirAsList(String path) {
        List<String> list = new ArrayList<>();

        String[] paths = new File(path).list();
        if (Objects.isNull(paths)) {
            return list;
        }

        for (final String p: paths) {
            list.add(path + File.separator + p);
        }

        return list;
    }
}
